<template>
    <div class="maskLoading" v-if="isLoading">
        <div class="loading">
            <div :style="{width : loadingWidth +'%' }"></div>
        </div>
        <div style="padding-left: 10px;">{{loadingWidth}}%</div>
    </div>
</template>

<script setup lang="ts">
    import {onMounted, reactive, ref, toRefs} from 'vue'
    import {
        Color,
        DirectionalLight,
        DirectionalLightHelper,
        HemisphereLight,
        HemisphereLightHelper,
        Mesh,
        MeshPhongMaterial,
        PerspectiveCamera,
        PlaneGeometry,
        Scene,
        WebGLRenderer
    } from 'three'
    import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js'
    import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader'
    // import internal from 'stream';
    import dat from 'dat.gui'
import { channel } from 'diagnostics_channel'
    console.log('dat==>',dat);

    /**
     * debug
     */
    const gui = new dat.GUI()
    
    const parameters = {
        color: 0xb3b3b3,
        opacity: 0.3,
        wheelsColor: 0xffffff,
        floorColor: 0xa4a4a4,
        directionalLightIntensity: 1,
        hemisphereLightIntensity: 0.5,
    }
    const loader = new GLTFLoader()
    const defaultMap = {
        x: 510,
        y: 128,
        z: 0,
    }
    const map = reactive(defaultMap)
    const {x, y, z} = toRefs(map)
    let scene:any, camera:any, renderer:any, controls:any, floor, dhelper, hHelper, directionalLight, hemisphereLight
    let isLoading = ref(true)
    let loadingWidth = ref(0)

    const setFloor = () => {
        // let floorGeometry = new PlaneGeometry(5000, 5000, 1, 1.1);
        let floorGeometry = new PlaneGeometry(5000, 5000, 1, 1.1);
        let floorMaterial = new MeshPhongMaterial({
            color: parameters.floorColor,
            // wireframe: true
        })
        floor = new Mesh(floorGeometry, floorMaterial);
        floor.rotation.x = -0.5 * Math.PI;
        // floor.position.y = -2.1;
        floor.position.y = -75;
        scene.add(floor)
    }


    const setLight = () => {
        directionalLight = new DirectionalLight(0xffffff, parameters.directionalLightIntensity)
        directionalLight.position.set(-4, 8, 4)
        dhelper = new DirectionalLightHelper(directionalLight, 5, 0xffffff)
        hemisphereLight = new HemisphereLight(0xffffff, 0xffffff, parameters.hemisphereLightIntensity)
        hemisphereLight.position.set(0, 8, 0)
        hHelper = new HemisphereLightHelper(hemisphereLight, 5)
        scene.add(directionalLight)
        scene.add(hemisphereLight)
    }

    const setCamera = () => {
        const {x, y, z} = defaultMap
        scene = new Scene();
        scene.background = new Color(0xffffff);
        camera = new PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000)
        camera.position.set(x, y, z)
        renderer = new WebGLRenderer()
        // 抗锯齿
        renderer.antialias = true;
        console.log('window.devicePixelRatio',window.devicePixelRatio);
        
        renderer.setPixelRatio(window.devicePixelRatio);

        renderer.setSize(innerWidth, innerHeight)
        document.body.appendChild(renderer.domElement)

    }
    const setControls = () => {
        controls = new OrbitControls(camera, renderer.domElement)
        controls.maxPolarAngle = 0.9 * Math.PI / 2
        controls.enableZoom = true
        controls.addEventListener('change', render)
    }


    const init = async () => {
        const gltf:any = await loadFile(`${import.meta.env.BASE_URL}models/tesla_2018_model_3/scene.gltf`)
        console.log('gltf===>',gltf);
        console.log('material===>',gltf.scene);
        
        setCamera()
        setLight()
        setFloor()
        setControls()
        scene.add(gltf.scene)

        console.log('camera===>',camera);

        
        

        gui.add(gltf.scene.position, 'y').min(-300).max(300).step(0.1).name('Elevation')
        gui.add(gltf.scene.position, 'x').min(-300).max(300).step(0.1).name('Horizontal').onChange(()=>{
            console.log('gltf.scene.position===>',gltf.scene.position);
            // camera.lookAt(gltf.scene.position);
        })
        isAutoFun()
        gui.add(controls, 'autoRotate').name('rotation');
        gui.add(gltf.scene, 'visible')
        setCarColor(parameters.color)
        gui.addColor(parameters,'color').onChange(()=>{
            setCarColor(parameters.color)
        })
        setGlassOpacity(parameters.opacity)
        gui.add(parameters, 'opacity').min(0).max(1).step(0.01).onChange(()=>{
            setGlassOpacity(parameters.opacity)
        })
        setWheelsColor(parameters.wheelsColor)
        gui.addColor(parameters,'wheelsColor').onChange(()=>{
            setWheelsColor(parameters.wheelsColor)
        })
        gui.addColor(parameters,'floorColor').onChange(()=>{
            setFloorColor(parameters.floorColor)
        })
        gui.add(parameters, 'directionalLightIntensity').min(0).max(1).step(0.01).onChange(()=>{

        })
        loop()
    }

    const loop = () => {
        requestAnimationFrame(loop)
        renderer.render(scene, camera)
        controls.update()
    }

    const isAutoFun = () => {
        controls.autoRotate = true
    }
    const stop = () => {
        controls.autoRotate = false
    }

    const render = () => {
        map.x = Number.parseInt(camera.position.x)
        map.y = Number.parseInt(camera.position.y)
        map.z = Number.parseInt(camera.position.z)
    }

    const setCarColor = (val:any) => {
        const currentColor = val
        scene.traverse((child: { isMesh: any; name: string | string[]; material: {
[x: string]: any; color: { set: (arg0: Color) => void; }; 
}; }) => {
            if (child.isMesh) {
                console.log('child.name===>',child.name)
                
                if(/door_/.test(child.name.toString())){
                    child.material.color.set(currentColor)
                }
            }
        })
    }

    const setGlassOpacity = (val:number)=>{
        scene.traverse((child: { isMesh: any; name: string | string[]; material: {
[x: string]: any; color: { set: (arg0: Color) => void; }; 
}; }) => {
            if (child.isMesh) {
                console.log('child.name===>',child.name)
                if(/glass_/.test(child.name.toString())){
                    console.log('glass_===>',child.material.opacity);
                    child.material.opacity = val;
                }
                if(/tembus_/.test(child.name.toString())){
                    console.log('glass_===>',child.material.opacity);
                    child.material.opacity = val;
                    console.log('glass_===>',child.material.opacity);
                }
                
            }
        })
    }
    
    const setWheelsColor = (val:any)=>{
        scene.traverse((child: { isMesh: any; name: string | string[]; material: {
[x: string]: any; color: { set: (arg0: Color) => void; }; 
}; }) => {
            if (child.isMesh) {
                console.log('child.name===>',child.name)
                if(/wheels/.test(child.name.toString())){
                    child.material.color.set(val)
                }
                
            }
        })
    }

    const setFloorColor = ( val:any ) => {
        scene.traverse((child)=>{
            if(child.type === "Mesh" && child.name === ''){
                console.log('child===>',child);
                child.material.color.set(val)
            }
        })
    }


    const loadFile = (url: string) => {
        return new Promise(((resolve, reject) => {
            loader.load(url,
                (gltf) => {
                    resolve(gltf)
                }, ({loaded,total}) => {
                    let load = Math.abs(loaded /total * 100)
                    loadingWidth.value = load

                    if (load >= 100) {
                        setTimeout(() => {
                            isLoading.value = false
                        }, 1000)
                    }
                    console.log((loaded / total * 100) + '% loaded')
                },
                (err) => {
                    reject(err)
                }
            )
        }))
    }
    const onResizeFun = (ev: any)=>{
        setCamera()
    }


    onMounted(() => {
        init()
        window.addEventListener('resize',onResizeFun)
    })
</script>

<style lang="less" scoped>
    body {
        margin: 0;
    }

    .maskLoading {
        background: #000;
        position: fixed;
        display: flex;
        justify-content: center;
        align-items: center;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        z-index: 1111111;
        color: #fff;
    }

    .maskLoading .loading {
        width: 400px;
        height: 20px;
        border: 1px solid #fff;
        background: #000;
        overflow: hidden;
        border-radius: 10px;

    }

    .maskLoading .loading div {
        background: #fff;
        height: 20px;
        width: 0;
        transition-duration: 500ms;
        transition-timing-function: ease-in;
    }

    canvas {
        width: 100%;
        height: 100%;
        margin: auto;
    }
</style>
